<?php
/**
 * php GEM Project
 * 
 * LICENSE
 * 
 * PHP System Architecture Enabling Rapid Application Deployment and Scalability
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @copyright Copyright (C) 2010 Zeletron LLC (http://zeletron.com)
 * @license http://gem.zeletron.com/license
 */

/*
 * GEM/Service/Service.php
 * 
 * The abstract service class defines an API common to extending service classes.
 * The class is not intended to be used directly. Extending classes will inherit the
 * common API features in addition to providing additional service-specific features.
 * 
 * @author David Joly
 * @link http://zeletron.com
 * 
 * @category GEM
 * @package GEM_Service
 */
abstract class GEM_Service_Service implements Zend_Acl_Resource_Interface
{	
	/** Service Response Codes */
	const RESPONSE_CODE_SUCCESS = 100;
	const RESPONSE_CODE_ERROR = 200;
	const RESPONSE_CODE_INVALID = 300;
	const RESPONSE_CODE_DENIED = 400;
	
	/**
	 * Service Response Objects
	 * 
	 * array('action' => GEM_Service_Response)
	 * 
	 * @var array
	 */
	protected $_response = array();
	
	/**
	 * Constructor 
	 * 
	 * @return void
	 * @throws GEM_Service_Exception
	 */
	public function __construct()
	{
		if(GEM_System::instance()->isServiceRegistered($this->_serviceType()))
			throw new GEM_Service_Exception("{$this->_serviceType()} is already running. Cannot create duplicate service instance.");
	}
	
	/**
	 * Returns a response issued by the specified service action method.
	 * 
	 * @param string $action The service action method
	 * @return GEM_Service_Response
	 * @throws GEM_Service_Exception
	 */
	public function getResponse($action)
	{
		if(!method_exists($this, $action))
			throw new GEM_Service_Exception("Method $action not found in class " . get_class($this));
		return array_key_exists($action, $this->_response) ? $this->_response[$action] : null;
	}
	
	/**
	 * Checks the service response array to verify the
	 * specified service has issued response.
	 * 
	 * @param string $action The service action method
	 * @return GEM_Service_Response
	 * @throws GEM_Service_Exception
	 */
	public function hasResponse($action)
	{
		if(!method_exists($this, $action))
			throw new GEM_Service_Exception("Method $action not found in class " . get_class($this));
		return array_key_exists($action, $this->_response) ? true : false;
	}
	
	/**
	 * Returns a response message issued by the specified action, if
	 * it exists.
	 * 
	 * @param string $action The service action method
	 * @return string
	 * @throws GEM_Service_Exception
	 */
	public function getMessage($action)
	{
		if(!method_exists($this, $action))
			throw new GEM_Service_Exception("Method $action not found in class " . get_class($this));
		if($this->hasResponse($action)) return $this->_response[$action]->getMessage();
	}
	
	/**
	 * Used by extending service class action methods to return a
	 * GEM_Service_Response object to the client. This method also
	 * saves the response object, which can be retrieved by client
	 * code via getResponse().
	 * @see GEM_Service_Service#getResponse()
	 * 
	 * @param string $action The service method issuing the response.
	 * @param int $status The service response code
	 * @param string $message | optional
	 * @param Zend_Form $form | optional
	 * @return GEM_Service_Response
	 * @throws GEM_Service_Exception
	 */
	protected function response($action,$status,$message = null,$form = null,$formPersist = true)
	{
		if(!method_exists($this, $action))
			throw new GEM_Service_Exception("Method $action not found in class " . get_class($this));
		$response = new GEM_Service_Response($status,$message,$form,$formPersist);
		if(array_key_exists($action, $this->_response)){
			//If a response already exists for the specified action method, remove it.
			unset($this->_response[$action]);
		}
		//Saving response object for later retrieval.
		$this->_response[$action] = $response;
		return $response;
	}
	
	/**
	 * Returns the object's class type, which is used by service control
	 * methods, start(), stop(), and restart(). The returned value is the
	 * service class's short name. Example:
	 * 
	 * 		The service class GEM_Service_User will return 'User'.
	 * 
	 * @return string
	 */
	protected function _serviceType()
	{
		$class = get_class($this);
		return substr($class,strrpos($class, "_") + 1);
	}
	
	/**
	 * When waking up, all responses that have already persisted for
	 * a single request must be removed.
	 * 
	 * @return void
	 */
	public function __wakeup()
	{
		//Array to store responses that have yet to persist for a request.
		$responses = array();
		foreach($this->_response as $action => $response){
			if($response->getPersisted() === false){
				$response->setPersisted(true);
				$responses[$action] = $response;
			}
		}
		//Reset response array
		$this->_response = $responses;
	}
}